# Copyright (C) 2006  Stephane Alnet
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 

#
# For more information visit http://carrierclass.net/
#

use strict;
use warnings;

package CCNCore::Handle;
use base qw( Jifty::Handle );

sub delete
{
    my $self = shift;
    my ( $table, @pairs ) = @_;
    
    # Always use the parent for _* and ChangeSet* tables.
    if( $table !~ /^_|^ChangeSet/ and $self->_need_changeset_delete($table) )
    {
        $self->_changeset_delete(@_);
    }
    else
    {
        $self->SUPER::delete(@_);
    }
}

=pod
    _need_changeset_delete
    
    Returns true iff the operation needs to be applied via a changeset.
=cut

sub _need_changeset_delete
{
    my $self = shift;
    my ($table) = @_;
    # XXX-URGENT
    return 0;
}

=pod
    _changeset_delete
    
    Create a changeset to mark the record as deleted.
=cut

sub _changeset_delete
{
    my $self = shift;
    my ($table,@pairs) = @_;

    # Build the list of IDs where we need to mark the records as deleted.
    my @bind  = ();
    my $where = 'WHERE ';
    while (my $key = shift @pairs) {
        $where .= $key . "=?" . " AND ";
        push( @bind, shift(@pairs) );
    }

    $where =~ s/AND $//;
    my $query_string = "SELECT id, is_active FROM " . $table . ' ' . $where;
    my $sth = $self->simple_query( $query_string, @bind );

    # For each ID that we need to delete.
    while( my $ary = $sth->fetchrow_arrayref )
    {
        my $id = $ary->[0];
        my $old_active = $ary->[1];

        # Create a single changeset record
        my $changeset_class = CCNCore::Model::ChangeSet->new();
        $changeset_class->create(
            table_name => $table,
            operation  => 'm',
            the_id     => $id,
        );
        my $changeset_id = $changeset_class->id;

        # Create a single changeset_value record
        my $cs_values_class = CCNCore::Model::ChangeSetValues->new();
        $cs_values_class->create(
            the_changeset => $changeset_id,
            column_name => 'is_active',
            old_value => $old_active,
            new_value => 'FALSE',
        );
    }
}

sub insert
{
    my $self = shift;
    my ( $table, @pairs ) = @_;

    # Always use the parent for _* and ChangeSet* tables.
    if( $table !~ /^_|^ChangeSet/ and $self->_need_changeset_insert($table) )
    {
        $self->_changeset_insert(@_);
    }
    else
    {
        $self->SUPER::insert(@_);
    }
    
}

sub _need_changeset_insert
{
    my $self = shift;
    my ($table) = @_;
    # XXX-URGENT
    return 0;
}

sub _changeset_insert
{
    my $self = shift;
    # $self->SUPER::insert(@_);
    my ( $table, @pairs ) = @_;

    # First create the record locally to obtain the ID.
    my $new_id = $self->SUPER::insert($table,'is_active','FALSE',@pairs);

    my $changeset_class = CCNCore::Model::ChangeSet->new();
    $changeset_class->create(
        table_name => $table,
        operation  => 'i',
        the_id => $new_id,
    );
    my $changeset_id = $changeset_class->id;

    unshift @pairs, 'is_active', 'TRUE';

    while( my $key = shift @pairs )
    {
        my $cs_values_class = CCNCore::Model::ChangeSetValues->new();
        my $value = shift @pairs;
        $cs_values_class->create(
            the_changeset => $changeset_id,
            column_name => $key,
            old_value => $key eq 'is_active' ? 'FALSE', undef,
            new_value => $value,
        );
    }
}

sub update_record_value
{
    my $self = shift;
    my %args = (
        table           => undef,
        column          => undef,
        is_sql_function => undef,
        primary_keys    => undef,
        @_
    );

    return 1 unless grep {defined} values %{$args{primary_keys}};

    my $table = $args{table};
    my $column = $args{column};

    # Always use the parent for _* and ChangeSet* tables.
    if( $table !~ /^_|^ChangeSet/ and $self->_need_changeset_update($table,$column) )
    {
        $self->_changeset_update(@_);
    }
    else
    {
        $self->SUPER::update_record_value(@_);
    }
}

sub _need_changeset_update
{
    my $self = shift;
    my ($table,$column) = @_;

    # XXX-URGENT
    return 0;
}

sub _changeset_update
{
    my $self = shift;
    my %args = (
        table           => undef,
        column          => undef,
        is_sql_function => undef,
        primary_keys    => undef,
        @_
    );

    # Gather the list of IDs and old_value/new_value records
    my @bind  = ();
    my $query = qq(SELECT id, "$args{column}");

    ## Look and see if the column is being updated via a SQL function.
    if ( $args{'is_sql_function'} ) {
        $query .= qq(, $args{value} );
    } else {
        $query .= ', ? ';
        push( @bind, $args{'value'} );
    }

    $query .= qq( FROM "$args{table}" );
    
    ## Constructs the where clause.
    my $where = 'WHERE ';
    foreach my $key ( keys %{ $args{'primary_keys'} } ) {
        $where .= $key . "=?" . " AND ";
        push( @bind, $args{'primary_keys'}{$key} );
    }
    $where =~ s/AND\s$//;

    my $query_str = $query . $where;
    my $sth = $self->simple_query( $query_str, @bind );

    while( my $ary = $sth->fetchrow_array_ref )
    {
        my $id = $ary->[0];
        my $old_value = $ary->[1];
        my $new_value = $ary->[2];

        my $changeset_class = CCNCore::Model::ChangeSet->new();
        $changeset_class->create(
            table_name => $table,
            operation  => 'm',
            the_id     => $id,
        );
        my $changeset_id = $changeset_class->id;

        my $cs_values_class = CCNCore::Model::ChangeSetValues->new();
        $cs_values_class->create(
            the_changeset => $changeset_id,
            column_name => $args{column},
            old_value => $old_value,
            new_value => $new_value,
        );
    }
}

1;

=pod



# A given user/group is going to have a validation policy.
# The policy points to a set of users or groups that must validate the
# change before it is applied.
# If the policy is empty then the changeset

sub mark_changeset_applied($)
{
    my ($cs_pk) = @_;

    sql_do(<<SQL,$cs_pk)
UPDATE changeset SET applied = 'true' WHERE pk = %
SQL
}


sub changeset_do(...)
{
    if(changeset_has_policy($cs_pk))
    {
        create_policy_action($cs_pk)
    }
    else
    {
        commit_changeset($cs_pk)
    }
}

=cut